package net.borlis.errors.annotations;

import net.borlis.errors.exceptions.ServerException;
import net.borlis.errors.exceptions.TranslatedException;
import net.borlis.errors.providers.common.ITranslatedExceptionProcessor;
import net.borlis.errors.providers.implementation.filebase.LocaleFileErrors;

import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.xml.bind.ValidationException;
import java.lang.annotation.Annotation;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author alex@borlis.net
 */
@Interceptor @TranslatedExceptionRegister
public class TranslatedExceptionInterceptor {

    private static final String DEFAULT_LOCALE = "de-DE";
    private static final String VALIDATION_CODE = "1200";

    @Inject
    private Logger logger;

    @Inject
    @LocaleFileErrors
    private ITranslatedExceptionProcessor translatedExceptionProcessor;

    @AroundInvoke
    public Object checkRunningCode(InvocationContext ctx) throws Exception {//NOPMD
        // there is a conflict between SONAR/CDI
        // -=-=-=-
        String locale = DEFAULT_LOCALE;
        try {
            // -=-=-=-=-=-
            logger.log(Level.FINE, "The class name: " + ctx.getMethod().getDeclaringClass().getName());
            logger.log(Level.FINE, "The method name: " + ctx.getMethod().getName());
            logger.log(Level.FINE, "The content data: " + ctx.getContextData().toString());
            // -=-=-=-=-=-
            Annotation[][] parametersAnnotations = ctx.getMethod().getParameterAnnotations();
            boolean foundMarkedAsRequestLocale = false;
            for (int i = 0; i < parametersAnnotations.length; i++) { // go by parameters
                Annotation[] parameterAnnotations = parametersAnnotations[i];
                for (Annotation annotation : parameterAnnotations) { // go by annotations
                    if (annotation instanceof RequestLocale) {
                        if (ctx.getParameters()[i] != null && ctx.getParameters()[i] instanceof String) {
                            if (foundMarkedAsRequestLocale) { //todo:: maybe better ValidationException? sprint#16
                                throw new IllegalStateException("there is two parameters marked as RequestLocale");
                            }
                            locale = String.valueOf(ctx.getParameters()[i]);
                            foundMarkedAsRequestLocale = true;
                        } else { //todo:: maybe better ValidationException? sprint#16
                            throw new IllegalArgumentException("the marked as RequestLocale parameter cannot be used");
                        }
                    }
                }
            }
            // -=-=-=-=-=-
            return ctx.proceed();
            // -=-=-=-=-=-
        } catch (TranslatedException te) {
            logger.log(Level.SEVERE, "translated exception", te);
            throw te;
        } catch (ValidationException ve) {
            logger.log(Level.SEVERE, "validation exception", ve);
            throw translatedExceptionProcessor.newTranslatedException(locale, VALIDATION_CODE, ve);
        } catch (ServerException se) {
            throw translatedExceptionProcessor.newTranslatedException(locale, se);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "unexpected exception", e);
            throw e;
        }
    }

}
